var code = [
    {
        title: "查看img控件属性",
        version: "版本1.0",
        author: "作者",
        code: "let obj = m.controlbar.but; for(let k in obj)if(typeof obj[k] == 'function'){log(k)};",
        describe: "功能描述"
    },
    {
        title: "改main高度",
        version: "版本1.0",
        author: "作者",
        code: "m.main.setSize(device.width,device.height*0.4)",
        describe: "功能描述"
    },
    {
        title: "设置图片",
        version: "版本1.0",
        author: "作者",
        code: "m.controlbar.but.setSource('')",
        describe: "功能描述"
    },
    {
        title: "sky加好友",
        version: "1.0",
        author: "luoluo334",
        code: `
var data = dialogs.rawInput("请输入好友链接")
// 对链接进行操作
var index;
if(-1 < (index=data.indexOf("?"))){
    data = "https://sky.thatg.co/"+data.substring(index);
}
log("最终结果：", data)

app.startActivity({ 
    action: "android.intent.action.VIEW", 
    data: data, 
    packageName: "com.tgc.sky.android", 
});
        `,
        describe: "在复制了sky好友链接后，需要带有'?'，可以直接使用sky打开添加"
    },
    {
        title: "米米的看板娘",
        version: "1.0.0",
        author: "luoluo334",
        code: `
let f = floaty.rawWindow(

  <vertical>

    <frame w="{{parseInt(device.width*0.63)+'px'}}" h="{{device.height*0.3+'px'}}">
      <webview id="web" bg="#00000000" />
    </frame>
    <img id="bar" bg="#50E09F00" h="50px"/>
  </vertical>);

ui.run(() => {
  let mimiUrl = "https://mi.js.org/live2d-widget/demo/demo.html";
  let tag = "loadOK";
  let init = 'if (screen.width < 768) {'
  +'  Promise.all(['
  +'    loadExternalResource(live2d_path + "waifu.css", "css"),'
  +'    loadExternalResource(live2d_path + "live2d.min.js", "js"),'
  +'    loadExternalResource(live2d_path + "waifu-tips.js", "js")'
  +'  ]).then(() => {'
  +'    initWidget({'
  +'      waifuPath: live2d_path + "waifu-tips.json",'
  +'      cdnPath: "https://cdn.jsdelivr.net/gh/fghrsh/live2d_api/"'
  +'    });'
  +'  });'
  +'}'
  // 删除右上角的github
  +'document.getElementsByTagName("body")[0].removeChild(document.getElementById("github"));'
  // 设置url带有auto参数
  +setUrlDataFromWeb.toString()
  +';setUrlDataFromWeb("'+tag+'");'

  f.web.setBackgroundColor(0);
  f.web.getBackground().setAlpha(0);
  f.web.loadUrl(mimiUrl);

  // 监控地址
  setInterval(()=>{
    if(false && f.web.url.indexOf(mimiUrl) < 0){
      f.web.stopLoading();
      if(confirm("不要离开我~\n是否重新载入？")){
        f.web.loadUrl(mimiUrl);
        initFun();
      }
    }
  },3000);

  // 初始化
  initFun();
  function initFun(){
    let inte = setInterval(() => {
      if(getUrlData(f.web) == tag) {
        runUrlDataByWeb(f.web,
          // 放大
          'document.getElementsByTagName("body")[0].style.zoom=3;'
          )
        clearInterval(inte);
      }
      runUrlDataByWeb(f.web,init);
    }, 200);
  }

        // { '0': 'https://oss.ucdl.pp.uc.cn/fs01/union_pack/PPAssistant_2522676_PP_247.apk?x-oss-process=udf%2Fpp-udf%2CJjc3LiMnJ3R%2Bf35%2B&apprd=39899',
        // '1': 'Mozilla/5.0 (Linux; Android 11; RMX2072 Build/RKQ1.200710.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.106 Mobile Safari/537.36',
        // '2': 'attachment;filename=PPAssistant_2522676_PP_247.apk',
        // '3': 'application/vnd.android.package-archive',
        // '4': 14798422 }
        // 链接，浏览器信息，文件名，mime接口类型，总长度
        // String url, String userAgent, String contentDisposition,String mimetype, long contentLength
  // 设置下载监听器
  f.web.setDownloadListener(function (data, deviceInfo, notknow1, type, notknow2) {
    if (type == "image/png")
      threads.start(function () {
        if (confirm("是否保存图片？")){
          files.ensureDir("/sdcard/脚本/米米的看板娘/");
          log(images.fromBase64(data).saveTo("/sdcard/脚本/米米的看板娘/"
                                + new Date().toLocaleString()+".png"));
        }
      });
  });
});

OnTouchListener(f,"bar",{
  dwonCode: 'setColor("#50117ACC");',
  moveLongClickCode: 'setColor("#50DC4C3F");',
  upSuf: 'setColor("#50E09F00");',
  upClickCode: 'toast("样品\\n成品正在...\\n长按关闭");',
  upLongClickCode: 'exit();',
  moveCode: 'let newX=fx+(event.getRawX()-downX);'//新的x坐标
  +'let newY=fy+(event.getRawY()-downY);'//新的y坐标
  +'f.setPosition(newX,newY);'//移动
});

// 续命
setInterval(()=>{},100000);

function setColor(str) {
  ui.run(()=>{
    f.bar.setBackgroundColor(colors.parseColor(str));
  })
}

function OnTouchListener(f,viewID,code){try{ eval("ViewObj=f."+viewID+";"); if(ViewObj==undefined) throw "在悬浮窗中未获取到id为\""+viewID+"\"+的视图组件"; }catch(err){ return false; } attributeDefined(code, [ ["scope", "10"] ,["longTime", "600"] ,["initCode"] ,["dwonCode"] ,["moveCode"] ,["moveLongClickCode"] ,["upMoveCode"] ,["upLongClickCode"] ,["upClickCode"] ,["upPre"] ,["upSuf"] ] ); var fx=fy=downX=downY=downTime=0; var longPress=true, moveLongClickTag = true; eval(code.initCode); ViewObj.setOnTouchListener( function(view, event){ switch(event.getAction()){ case event.ACTION_DOWN: ViewObj.setAlpha(ViewObj.alpha*0.8); downX = event.getRawX(); downY = event.getRawY(); fx=f.getX(); fy=f.getY(); downTime = new Date().getTime(); longPress=true; eval(code.dwonCode); return true; case event.ACTION_MOVE: if(Math.abs(event.getRawX()-downX)>code.scope||Math.abs(event.getRawY()-downY)>code.scope){ longPress=false; } if(moveLongClickTag && new Date().getTime()-downTime>code.longTime){ moveLongClickTag=false; eval(code.moveLongClickCode);} eval(code.moveCode); return true; case event.ACTION_UP: ViewObj.setAlpha(ViewObj.alpha*1.25); moveLongClickTag=true; eval(code.upPre); if( new Date().getTime()-downTime<code.longTime ){ longPress=false; } if( Math.abs(event.getRawX()-downX)>code.scope||Math.abs(event.getRawY()-downY)>code.scope ){ eval(code.upMoveCode); }else{ if(longPress){ eval(code.upLongClickCode); }else{ eval(code.upClickCode);} } eval(code.upSuf); return true; } return true; } ); function attributeDefined(obj, arr) { try { arr.forEach(a => { if (a != undefined && eval("(obj." + a[0] + ")") == undefined) { if (a.length == 1) a.push(""); eval("obj." + a[0] + "=\"" + a[1] + "\""); } }); } catch (e) { log(e) } return obj; } }
function getAttributeByObject(obj) {

  if (typeof re != "object") re = {};
  if (typeof obj != "object") return re;

  let name;
  for (let key in obj) {
      try {
          name = typeof obj[key];
      } catch (e) {
          console.error(e)
          name = "accident";
      }
      if (typeof re[name] != "object")
          re[name] = [];
      re[name].push(key);
  }

  return re;
}
function setUrlDataFromWeb(data, tag) {

  switch (typeof data) {
      case "string": break;
      case "object": data = JSON.stringify(data); break;
      default: throw "参数不是字符串或者对象类型！";
  }
  tag = tag || "?auto.js=";
  if (data.length > 2048)
      console.warn("参数过长，可能会引发异常。");
  window.history.pushState("", "", tag + data);
}
function getUrlData(action, tag) {

  try {
      tag = tag || '?auto.js=';
      let startIndexOf = action.url.indexOf(tag);
      if (startIndexOf < 0) throw "未获取到参数";
      // 拿到数据
      let data = action.url.substring(startIndexOf + tag.length);
      // 还原地址
      setUrlNotLoad(action, action.url.substring(0, startIndexOf));
      return decodeURIComponent(data);
  } catch (e) {
      console.warn(e);
  }
  return false;
}
function runUrlDataByWeb(action, code) {
  action.loadUrl("javascript:" + code);
}
function setUrlNotLoad(action, url) {
  action.loadUrl("javascript:window.history.pushState('','', " + url + ");");
}



/* */
        `,
        describe: "悬浮窗看板娘"
    },
    {

        title: "截图翻译2",
        version: "2.2.0",
        author: "luoluo334",
        code: `
/**

 * Copyright © 2020 luoluo334.All rights reserved. 

 * FileName: 截图翻译2.js
 * Author: luoluo334
 * Version: 2.2
 * Date: 2020-12-12
 * Description: 截图翻译、文本翻译
 * 
 * 更新：
 * v2.2
 * 添加版权说明
 * v2.1 
 * 横屏隐藏图片悬浮窗不友好
 * v2.0
 *       悬浮窗使用原生的
 *       按钮增加翻译中状态
 *       截图翻译会在屏幕上显示截图
 *       悬浮窗操作逻辑改变：
 * 背景：长按打开窗口操作界面
 * 任意控件滑动：移动窗口
 * 按钮：  点击截图翻译，长按 显示截图
 * 输入框：点击输入，长按翻译输入框
 * 翻译：  点击复制，长按退出
 * 图片悬浮窗：  点击隐藏，长按切换自动隐藏时间
 *         并重置本次显示时间，通过按钮显
 *         示的不会自动隐藏，需要手动隐藏。
 */

// 翻译对象
translate = {
    // 当前文字
    text: "",
    // 翻译结果
    result: "",
    // 设置文字，失败返回false，成功返回上一个text文字
    set: function(text){
        if(typeof text == "string"){
            let re = this.text;
            this.text = text;
            return re;
        }
        return false;
    },
    
    // 翻译文字
    get: function(text){
        if(typeof text == "string") this.text = text;
        // 翻译，由于在翻译函数之前，所以使用对象名调用
        try{
            this.result = youdao(text);
        }catch(e){
            console.error(e)
        }
        return this.result;
    },
}
// 图片识别对象
ocr = {
    // 当前图片
    image: null,
    // 识别结果
    text: "",
    // 提交图片进行识别
    commit: function(image){
        if(image) this.image = image;
        // 提交图片到有道的ocr服务器
        this.text = youdaoOCR(image);;
        return this.text;
    }
}
// 截图对象，xAdapter yAdapter，分别为竖屏与横屏下状态栏的宽度
screenshot = {
    window: null,       // 悬浮窗对象
    image: null,        // 截图图片
    windowImage: null,  // 图片悬浮窗
    imgX: 0,            // 图片悬浮窗位置
    imgY: 0,
    imgTime: 5000,      // 自动隐藏时间
    switchTag: false,   // 切换标记
    timeRemaining: -1,  // 剩余时间，负数且切换标记为 true时会切换
    moveTimeout: setTimeout(()=>{},10),  // 定时器
    // 创建
    create: function(style,styleImg){
        let t = screenshot;
        // 创建悬浮窗
        t.window = floaty.rawWindow(style);
        t.windowImage = floaty.rawWindow(styleImg);
        return t.window;
    },
    // 截图
    screenshot: function(){
        let t = screenshot;
        let x,y,w,h;
        x = t.window.getX();
        y = t.window.getY();
        w = t.window.getWidth();
        h = t.window.getHeight();
        // 状态栏宽度
        try{
            xAdapter;
        }catch(e){
            xAdapter = 113;
        }
        try{
            yAdapter;
        }catch(e){
            yAdapter = 113;
        }
        // 将悬浮窗移开
        t.window.setPosition(device.width+1,device.height + 1);
        // 给点时间移动悬浮窗
        sleep(100);
        // 将图片缓存清理掉，在还没有图片缓存时会抛异常
        try{
            t.image.recycle();
        }catch(e){}

        // 处理一：不能越界，还有状态需要处理
        {   // 处理越界问题
            if (x < 0) x = 0;
            if (y < 0) y = 0;
            if (device.width < x) x = device.width;
            if (device.height < y) y = device.height;
            if (w < 1) return "截图失败！宽度小于1！";
            if (h < 1) return "截图失败！高度小于1！";
            if (device.width < x + w) {
                w = device.width - x;
                if (w < 1) return "截图失败！x过大：" + x;
            }
            if (device.height < y + h) {
                h = device.height - y;
                if (h < 1) return "截图失败！y过大：" + y;
            }
        }
        
        // 根据手机来适配，优先匹配 2（横屏）不匹配一律归类为竖屏
        // 截图并将图片保存
        if (context.getResources().getConfiguration().orientation == 2){
            // 处理二： 处理横屏，x不能超过 device.width - xAdapter
            if (device.width-xAdapter < y) y = device.width-xAdapter;
            if (device.width-xAdapter < x + w) {
                w = device.width-xAdapter - x;
                if (w < 1) return "截图失败！x过大：" + x;
            }
            t.image = images.clip(captureScreen(), x + xAdapter, y, w, h);
        } else {
            // 处理二： 处理竖屏，y不能超过 device.height - yAdapter
            if (device.height-yAdapter < y) y = device.height-yAdapter;
            if (device.height-yAdapter < y + h) {
                h = device.height-yAdapter - y;
                if (h < 1) return "截图失败！y过大：" + y;
            }
            t.image = images.clip(captureScreen(), x, y + yAdapter, w, h);
        }
        // 将悬浮窗移动回来
        t.window.setPosition(x,y);
        return t.image;
    },
    // 修改悬浮窗的图片
    upImgByBase64: function(imgBase64,w,h){
        threads.start(function(){
            // 获取图片的数据
            if(typeof w != "number" || typeof h != "number"){
                let img = images.fromBase64(imgBase64);
                w = img.getWidth();
                h = img.getHeight();
                img.recycle();
            }
            ui.run(()=>{
                screenshot.windowImage.setSize(w,h);
                screenshot.windowImage.img.setSource("data:image/png;base64,"+imgBase64);
            })
        })
        // 显示一会儿悬浮窗
        this.showImg(2);
    },
    upImgByImg: function(img) {
        this.upImgByBase64(images.toBase64(img), img.getWidth(), img.getHeight());
    },
    // 移动图片悬浮窗，返回值 true为显示，false为隐藏。
    moveImg: function() {
        let t = screenshot;
        t.noMove = false;    // 每次移动都会设置标记
        if(t.windowImage.getX() > device.width){
            // 还原
            t.windowImage.setPosition(t.imgX,t.imgY);
            return true;
        }else{
            // 隐藏
            // 保存当前位置
            t.imgX = t.windowImage.getX();
            t.imgY = t.windowImage.getY();
            t.windowImage.setPosition(device.width + 1, device.height + 1);
            return false;
        }
    },
    // 切换显示状态，传入参数则一定是显示，传入整数则一直显示，否则显示一定时间 imgTime。
    showImg: function(tag) {
        let t = screenshot;
        switch(tag){
            case 1:  // 一直显示
                if(t.windowImage.getX() > device.width) t.moveImg();
                t.switchTag = false;
                break;
            case 2:  // 显示
                if(t.windowImage.getX() > device.width) t.moveImg();
                t.setTimeRemaining();
                t.switchTag = true;
                break;
            case 3:  // 隐藏
                if(t.windowImage.getX() <= device.width) t.moveImg();
                t.switchTag = false;
                break;
            default: // 切换
                // 如果是显示，那么创建定时器
                if(t.moveImg()){
                    t.setTimeRemaining();
                    t.switchTag = true;
                }
        }
    },
    // 将默认等待时间给到剩余等待时间
    setTimeRemaining: function () {
        ST.screenshot.timeRemaining = ST.screenshot.imgTime;
    },
    // 设置默认等待时间
    setImgTime: function() {
        threads.start(function(){
            let num = rawInput("请输入图片自动消失时间，单位：毫秒（ms）");
            if(isNaN(num)) toastLog("修改失败！不是一个有效的数字！", num);
            else {
                screenshot.imgTime = num;
                toast("修改成功！修改为："+screenshot.imgTime);
            }
        })
    }
}
// 编辑框id edit，翻译框id show
ST = {
    survival: true,
    anim: false,
    translate: translate,
    ocr: ocr,
    screenshot: screenshot,
    // 运行，可选参数，悬浮窗样式
    run: function(style,styleImg){
        let w = ST.screenshot.create(style,styleImg);
        // 开启一个线程来处理动画
        threads.start(function () {
            // sleep(1000);
            let angle = 0;
            while (ST.survival){
                // 处理动画
                if (ST.anim){
                    ui.run(() => {
                        ST.screenshot.window.but.setRotation(angle);
                        angle += 5;
                        if (angle > 360)
                            angle -= 360;
                    });
                }
                // 处理图片悬浮窗
                if(ST.screenshot.switchTag && ST.screenshot.timeRemaining < 0){
                    ST.screenshot.moveImg();
                    ST.screenshot.switchTag = false;
                }
                ST.screenshot.timeRemaining -= 50;  // 剩余时间减去本次等待时间
                sleep(50);
            }
        })
        return w;
    },
    // 将文字提交翻译并设置到悬浮窗中，text 要翻译的文字， tip 遇到错误时的提示语句
    translateFun: function(text, tip){
        if(text!=null && text!=undefined && text!=""){
            // 更新编辑框文字（ui）
            ui.run(()=>{
                ST.screenshot.window.edit.setText(text);
            })
            // 提交到翻译
            let result = ST.translate.get(text);
            // 将结果显示到悬浮窗上，提示用户翻译成功（ui）
            ui.run(()=>{
                ST.screenshot.window.show.setText(result.toString())
                ST.screenshot.window.but.setText("🟢");
            });
            tip = true;
        }else{
            toastLog("翻译失败：", tip);
            // 提示用户翻译失败（ui）
            ui.run(()=>{
                ST.screenshot.window.but.setText("🟠");
            });
            tip = false;
        }
        // 一段时间后恢复 （ui）
        setTimeout(()=>{ui.run(()=>{
            ST.screenshot.window.but.setText("⚪")
        })}, 3000);
        return tip;
    },
    // 截图翻译
    commit: function(){
        ST.anim = true; // 动画标记
        // 截图
        let image = ST.screenshot.screenshot();
        // 将图片设置到图片悬浮窗中
        ST.screenshot.upImgByImg(image);
        // 提交ocr
        let text = ST.ocr.commit(images.toBase64(image));
        ST.translateFun(text, "未识别到文字");
        ST.anim = false;
        ui.run(() => { ST.screenshot.window.but.setRotation(0); });
        // 释放图片
        image.recycle();
    },
    // 文字翻译，手动提交
    submit: function(){
        ST.anim = true; // 动画标记
        // 获取当前悬浮窗的文字
        let text = ST.screenshot.window.edit.text();
        ST.translateFun(text, "未输入文字");
        ST.anim = false;
        ui.run(() => { ST.screenshot.window.but.setRotation(0); });
    }
}
// 请求截图权限
requestScreenCapture();
let style = 
<frame bg="#50775577" id="main" >
    <vertical>
        <horizontal padding="5dp">
            <button id="but" style="Widget.AppCompat.Button.Colored" w="44dp">⚪</button>
            <input id="edit" textColor="#90ffeeff" textSize="14dp" hint="要翻译的内容" lines="3" bg="#40993322"/>
        </horizontal>
        <text id="show" h="*" bg="#80339922"/>
    </vertical>
</frame>;
let styleImg = <frame id="main" w="*" h="*"> 
<img id="img" padding="3dp" src="https://img04.sogoucdn.com/app/a/07/6a227f646311c508f26165bd0d7e7a98" bg="#70112233"  w="*" h="*"/> 
</frame>;
// 创建悬浮窗（2个）
let w = ST.run(style,styleImg);

// 设置悬浮窗位置
w.setPosition(device.width*0.4,device.height*0.2);
// 隐藏截图悬浮窗
ST.screenshot.showImg();

let floatyMove = 'let newX=fx+(event.getRawX()-downX);'//新的x坐标
+'let newY=fy+(event.getRawY()-downY);'//新的y坐标
+'f.setPosition(newX,newY);'//移动

// 绑定图片悬浮窗操作
OnTouchListener(ST.screenshot.windowImage,"main",{
    upClickCode: 'ST.screenshot.showImg();',
    upLongClickCode: 'ST.screenshot.setImgTime();',
    moveCode: floatyMove+'ST.screenshot.setTimeRemaining();'
})
// 绑定主悬浮窗操作
OnTouchListener(w,"main",{
    upClickCode: 'toast("你好呀~\\n"+new Date().toLocaleTimeString().toString().substring(10));',
    upLongClickCode: 'floatyShape(w);',
    moveCode: floatyMove
})
// 按钮
OnTouchListener(w,"but",{
    upClickCode: 'threads.start(ST.commit);',           // 截图翻译
    moveLongClickCode: 'ST.screenshot.showImg(true);',  // 显示截图悬浮窗
    moveCode: floatyMove
})
// 翻译（显示）
OnTouchListener(w,"show",{
    upClickCode: 'let text = ST.screenshot.window.show.text() + "";'
                +'setClip(text);'
                +'toast("复制长度 ", text.length);', // 复制操作
    upLongClickCode: 'toastLog("生活愉快，下次见~");'
                +'exit();',                         // 显示截图悬浮窗
    moveCode: floatyMove
})

/*
// 点击 悬浮窗外取消锁定
w.edit.on("key", function(keyCode, event){
    if(event.getAction() == event.ACTION_DOWN && keyCode == keys.back){
        w.disableFocus();
        event.consumed = true;
    }
});
// 点击 输入框可以弹出输入法
w.edit.on("touch_down", ()=>{
    w.requestFocus();
    w.edit.requestFocus();
});*/
// 长按 输入框进行翻译
w.edit.on("long_click", ()=>{
    // 手动翻译
    threads.start(ST.submit);
});

setInterval(()=>{
    try{
        ST.screenshot.window.getX()
    }catch(e){
        ST.survival = false;
        exit();
    }
},1000)

toast("点击和长按都有功能")




//////////////////////////////////////////

//////////////////////////////////////////

//////////////////////////////////////////

/**
 * 对悬浮窗中指定的控件绑定事件
 * @param {FloatyWindow} f 悬浮窗
 * @param {String} viewID 控件id
 * @param {Object} code 操作代码
 */
function OnTouchListener(f,viewID,code){try{ eval("ViewObj=f."+viewID+";"); if(ViewObj==undefined) throw "在悬浮窗中未获取到id为\""+viewID+"\"+的视图组件"; }catch(err){ return false; } attributeDefined(code, [ ["scope", "10"] ,["longTime", "600"] ,["initCode"] ,["dwonCode"] ,["moveCode"] ,["moveLongClickCode"] ,["upMoveCode"] ,["upLongClickCode"] ,["upClickCode"] ,["upPre"] ,["upSuf"] ] ); var fx=fy=downX=downY=downTime=0; var longPress=true, moveLongClickTag = true; eval(code.initCode); ViewObj.setOnTouchListener( function(view, event){ switch(event.getAction()){ case event.ACTION_DOWN: ViewObj.setAlpha(ViewObj.alpha*0.8); downX = event.getRawX(); downY = event.getRawY(); fx=f.getX(); fy=f.getY(); downTime = new Date().getTime(); longPress=true; eval(code.dwonCode); return true; case event.ACTION_MOVE: if(Math.abs(event.getRawX()-downX)>code.scope||Math.abs(event.getRawY()-downY)>code.scope){ longPress=false; } if(moveLongClickTag && new Date().getTime()-downTime>code.longTime){ toast("↑UP↑"); moveLongClickTag=false; eval(code.moveLongClickCode);} eval(code.moveCode); return true; case event.ACTION_UP: ViewObj.setAlpha(ViewObj.alpha*1.25); moveLongClickTag=true; eval(code.upPre); if( new Date().getTime()-downTime<code.longTime ){ longPress=false; } if( Math.abs(event.getRawX()-downX)>code.scope||Math.abs(event.getRawY()-downY)>code.scope ){ eval(code.upMoveCode); }else{ if(longPress){ eval(code.upLongClickCode); }else{ eval(code.upClickCode);} } eval(code.upSuf); return true; } return true; } ); function attributeDefined(obj, arr) { try { arr.forEach(a => { if (a != undefined && eval("(obj." + a[0] + ")") == undefined) { if (a.length == 1) a.push(""); eval("obj." + a[0] + "=\"" + a[1] + "\""); } }); } catch (e) { log(e) } return obj; } }
/**
 * 传入一个悬浮窗即可对悬浮窗进行大小与位置的操作
 * @param {FloatyWindow} window 悬浮窗对象
 */
function floatyShape(window) {
    toastLog("进入悬浮窗编辑模式！");
    try{
      window.getX();
    }catch(e){
      log("似乎不是一个悬浮窗！", e , window);
      return false;
    }
    let backup = {
      w: window.width,
      h: window.height,
      x: window.getX(),
      y: window.getY()
    }
    let step = 10;
    let editF = floaty.rawWindow(<vertical id="main" bg="#2022ff00" padding="5dp">
        <vertical>
          <horizontal gravity="center">
            <button id="back"      text="还原" padding="0" w="50dp"/>
            <button id="left"      text="-"    padding="0" w="50dp"/>
            <text>步长：</text>
            <text id="step">10</text>
            <button id="right"     text="+"    padding="0" w="50dp"/>
            <button id="exit"      text="退出" padding="0" w="50dp"/>
          </horizontal>
          <horizontal gravity="center">
            <button id="sizesubx"    text="x缩小" padding="0" w="50dp"/>
            <button id="sizeaddx"    text="x增大" padding="0" w="50dp"/>
            <text w="10dp"/>
            <button id="pointsubx"  text="左移" padding="0" w="50dp"/>
            <button id="pointaddx" text="右移" padding="0" w="50dp"/>
          </horizontal>
          <horizontal gravity="center">
            <button id="sizesuby"    text="y缩小" padding="0" w="50dp"/>
            <button id="sizeaddy"    text="y增大" padding="0" w="50dp"/>
            <text w="10dp"/>
            <button id="pointsuby"  text="上移" padding="0" w="50dp"/>
            <button id="pointaddy" text="下移" padding="0" w="50dp"/>
          </horizontal>
        </vertical>
        <View h="1dp" bg="#00ff00" margin="5dp"></View>
        <horizontal h="{{device.height*0.2+'px'}}">
          <text id="resize" bg="#40004411" w="{{device.width*0.4+'px'}}" h="*" gravity="center">调整大小</text>
          <text id="repoint" bg="#40001144" w="*" h="*" gravity="center">移动位置</text>
        </horizontal>
    </vertical>)
  
    OnTouchListener(editF,"main",{
        moveCode: 'let newX=fx+(event.getRawX()-downX);'//新的x坐标
                + 'let newY=fy+(event.getRawY()-downY);'//新的y坐标
                + 'f.setPosition(newX,newY);',//移动
        upLongClickCode: 'toast("退出编辑模式");'
                        +'editF.close();',
        upClickCode: 'toast("嘤嘤嘤~");'
    })

    editF.main.on("long_click", ()=>{ toast("退出编辑模式"); editF.close(); });
    editF.exit.click( ()=>{ toast("退出编辑模式"); editF.close();});
    editF.back.click( ()=>{ r("window.setSize(backup.w, backup.h); window.setPosition(backup.x, backup.y);")});
    editF.step.click( ()=>{ upText(dialogs.rawInput("修改步长，请输入整数")) });
    editF.left.click( ()=>{ upText(--step) });
    editF.right.click(()=>{ upText(++step) });
  
    editF.sizesubx.click(()=>{ r("window.setSize(window.width-step,window.height)")});
    editF.sizeaddx.click(()=>{ r("window.setSize(window.width+step,window.height)")});
    editF.sizesuby.click(()=>{ r("window.setSize(window.width,window.height-step)")});
    editF.sizeaddy.click(()=>{ r("window.setSize(window.width,window.height+step)")});
  
    editF.pointsubx.click(()=>{ r("window.setPosition(window.getX()-step,window.getY())")});
    editF.pointaddx.click(()=>{ r("window.setPosition(window.getX()+step,window.getY())")});
    editF.pointsuby.click(()=>{ r("window.setPosition(window.getX(),window.getY()-step)")});
    editF.pointaddy.click(()=>{ r("window.setPosition(window.getX(),window.getY()+step)")});
  
    OnTouchListener(editF,"resize",{
      f:window,
      moveCode: 'let moveX=(event.getRawX()-downX)/10;'//新的x坐标
      +'let moveY=(event.getRawY()-downY)/10;'//新的y坐标
      +'code.f.setSize(parseInt(code.f.width)+parseInt(moveX), parseInt(code.f.height)+parseInt(moveY));' // 设置大小
    })
    OnTouchListener(editF,"repoint",{
      f: window,
      moveCode: 'let moveX=(event.getRawX()-downX)/10;'//新的x坐标
      +'let moveY=(event.getRawY()-downY)/10;'//新的y坐标
      +'code.f.setPosition(parseInt(code.f.getX())+parseInt(moveX), parseInt(code.f.getY())+parseInt(moveY));' // 设置大小
    })
  
  
    // 运行更新ui的代码字符串
    function r(code) {
      ui.run(()=>{
        eval(code);
      })
    }
    // 刷新文字
    function upText(num) {
      num = parseInt(num);
      if(isNaN(num)) {
        toastLog("不是一个有效的数字！", num)
        return false;
      }
      step = num;
      r("editF.step.setText(step.toString());");
    }
}
/** sha256唯一编码计算 */
function SHA256(s) {
    var chrsz = 8;
    var hexcase = 0;
    function safe_add(x, y) {
        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xFFFF);
    }
    function S(X, n) { return (X >>> n) | (X << (32 - n)); }
    function R(X, n) { return (X >>> n); }
    function Ch(x, y, z) { return ((x & y) ^ ((~x) & z)); }
    function Maj(x, y, z) { return ((x & y) ^ (x & z) ^ (y & z)); }
    function Sigma0256(x) { return (S(x, 2) ^ S(x, 13) ^ S(x, 22)); }
    function Sigma1256(x) { return (S(x, 6) ^ S(x, 11) ^ S(x, 25)); }
    function Gamma0256(x) { return (S(x, 7) ^ S(x, 18) ^ R(x, 3)); }
    function Gamma1256(x) { return (S(x, 17) ^ S(x, 19) ^ R(x, 10)); }
    function core_sha256(m, l) {
        var K = new Array(0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0xFC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x6CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2);
        var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
        var W = new Array(64);
        var a, b, c, d, e, f, g, h, i, j;
        var T1, T2;
        m[l >> 5] |= 0x80 << (24 - l % 32);
        m[((l + 64 >> 9) << 4) + 15] = l;
        for (var i = 0; i < m.length; i += 16) {
            a = HASH[0];
            b = HASH[1];
            c = HASH[2];
            d = HASH[3];
            e = HASH[4];
            f = HASH[5];
            g = HASH[6];
            h = HASH[7];
            for (var j = 0; j < 64; j++) {
                if (j < 16) W[j] = m[j + i];
                else W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
                T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
                T2 = safe_add(Sigma0256(a), Maj(a, b, c));
                h = g;
                g = f;
                f = e;
                e = safe_add(d, T1);
                d = c;
                c = b;
                b = a;
                a = safe_add(T1, T2);
            }
            HASH[0] = safe_add(a, HASH[0]);
            HASH[1] = safe_add(b, HASH[1]);
            HASH[2] = safe_add(c, HASH[2]);
            HASH[3] = safe_add(d, HASH[3]);
            HASH[4] = safe_add(e, HASH[4]);
            HASH[5] = safe_add(f, HASH[5]);
            HASH[6] = safe_add(g, HASH[6]);
            HASH[7] = safe_add(h, HASH[7]);
        }
        return HASH;
    }
    function str2binb(str) {
        var bin = Array();
        var mask = (1 << chrsz) - 1;
        for (var i = 0; i < str.length * chrsz; i += chrsz) {
            bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i % 32);
        }
        return bin;
    }
    function Utf8Encode(string) {
        string = string.replace(/\r\n/g, "\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    }
    function binb2hex(binarray) {
        var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
        var str = "";
        for (var i = 0; i < binarray.length * 4; i++) {
            str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) +
                hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 0xF);
        }
        return str;
    }
    s = Utf8Encode(s);
    return binb2hex(core_sha256(str2binb(s), s.length * chrsz));
}
/** 有道字符计算 */
function truncate(q) {
    var len = q.length;
    if (len <= 20) {
        return q;
    }
    return q.substring(0, 10) + len + q.substring(len - 10, len);
}

/**
*  有道翻译，传入需要翻译的文本
* @param {String} text     需要翻译的文本
* @returns {String}    返回翻译之后的文本
*/
function youdao(text) {
    if(typeof text == "object") text += "";
    //创建变量
    let appKey = "5990afed5e0ed6c3";    // 应用id
    let key = "fLhZ4rXjhUfEdmnuDuFlJarocpZvJsXq";
    let salt = (new Date).getTime();
    let curTime = Math.round(new Date().getTime() / 1000);
    let query = text;
    let str1 = appKey + truncate(query) + salt + curTime + key;
    let sign = SHA256(str1);
    let from = "auto";
    let to = "auto";

    //上传的数据
    let data = {
        q: query,//待翻译文本
        appKey: appKey,//应用ID
        salt: salt,//UUID
        from: from,//源语言
        to: to,//目标语言
        sign: sign,//签名
        signType: "v3",//签名类型
        curtime: curTime//当前UTC时间戳(秒)
    }
    //进行翻译
    let resp;
    try {
        resp = http.post("https://openapi.youdao.com/api", data);
        resp = resp.body.json().translation;
    } catch (e) {
        log("本次耗时：" + (new Date().getTime() - salt) + "ms");
        log("翻译失败！错误信息：", e);
        resp = "翻译失败";
    }
    //返回翻译后的文字
    return resp;
}
/**
*  有道OCR，传入需要识别的图片
* @param {Base64} img  需要识别的图片
* @returns {String}    返回翻译之后的文本
*/
function youdaoOCR(img) {
    if(typeof img == "object") img += "";
    //创建变量
    let langType = "auto";      // 识别类型
    let detectType = "10012";   // 按行识别类型
    let imageType = 1;          // 图片类型
    let appKey = "5990afed5e0ed6c3";
    let key = "fLhZ4rXjhUfEdmnuDuFlJarocpZvJsXq";
    let salt = (new Date).getTime();
    let curTime = Math.round(new Date().getTime() / 1000);
    let sha256Str = appKey + truncate(img) + salt + curTime + key;
    let sign = SHA256(sha256Str);
    let docType = "json";       // 响应类型
    let signType = "v3"

    //上传的数据
    let data = {
        img: img,               // 要识别的图片，需要Base64编码
        langType: langType,     // 要识别的语言类型
        detectType: detectType, // 识别类型，按行识别
        imageType: imageType,   // 图片类型，目前只支持Base64
        appKey: appKey,         // 应用ID
        salt: salt,             // UUID
        sign: sign,             // 签名
        docType: docType,       // 服务器响应类型，目前只支持json
        signType: signType,     // 签名类型
        curtime: curTime        //当前UTC时间戳(秒)
    }

    //进行翻译
    let resp="";
    try {
        let r = http.post("https://openapi.youdao.com/ocrapi", data);
        r.body.json().Result.regions.forEach(line=>{
            line.lines.forEach(word=>{
                resp += word.text+"\n";
            })
        });
    } catch (e) {
        log("本次耗时：" + (new Date().getTime() - salt) + "ms");
        log("识别失败！错误信息：" , e);
        resp = "识别失败";
    }
    //返回翻译后的文字
    return resp;
}
        `,
        describe: "功能描述"
    },
    {

        title: "夜间模式",
        version: "1.0.0",
        author: "luoluo334",
        code: `
var color=rawInput("输入颜色值，示例：#40112233");//输入颜色值
if(color==null || color.length==0 || /#[a-fA-F0-9]{6}$/.test(color)) color="#40000000";//校验颜色值
var w=floaty.rawWindow("<frame bg=\""+color+"\"/>");//创建悬浮窗
var deviation=200;//设置偏移量
w.setSize(device.width*3, device.height+deviation);//设置大小为全屏
w.setPosition(-deviation, -deviation);//XY轴向左上偏移
w.setTouchable(false);//设置不接收触摸操作
let time = rawInput("输入时间，单位（分钟,m）");
if(!(0 <= time)) time = 60;// 不是数字或小于0则赋值60
setTimeout(()=>{ w.close()}, 1000*60*time);//1小时后退出
        `,
        describe: "代码挺精简的，使用较复杂"
    },
    {

        title: "标题",
        version: "1.0.0",
        author: "luoluo334",
        code: `
/*var path=chooseFile();
log( path.substring(path.lastIndexOf("/")+1) );
*/
toastLog(chooseFile())

function chooseFile(path){
    try{ fileIcon;}catch(e){fileIcon="🤪"}
    try{ dirIcon;}catch(e){dirIcon="📂"}
    if(path==undefined){
        path=files.getSdcardPath();
    }
    var items, fileList, dirList, ch;
    //选择或退出选择文件
    while(files.isDir(path)){
        items=[ "🔙上一级", "❎退出", "*️⃣根目录", "🔎搜索"];
        dirList=[];
        fileList=[];
        //获取子文件与子文件夹
        files.listDir(path, function(name){
            if( files.isFile( files.join( path, name)) ){
                fileList.push(name);
            } else {
                dirList.push(name);
            }
            return false;
        });
        //排序
        dirList=dirList.sort((a, b) => a.localeCompare(b));
        fileList=fileList.sort((a, b) => a.localeCompare(b));
        //给文件名字随机生成一个前缀并保存到数组items中
        fileList.forEach(n=>{
            items.push(fileIcon+n);
            fileIcon=randomIcon();
        });
        dirList.forEach(n=>{
            items.push(dirIcon+n);
        });
        ch=dialogs.select("当前位置："+path, items);
        switch(ch){
            case -1: ch;
            case 0: 
                var len=path.lastIndexOf("/");
                if(len==path.length-1){
                    len=path.lastIndexOf( "/", len-1);
                }
                path=path.substring( 0, len); 
                break;
            case 1: 
                toastLog("退出文件选择");
                return null;
            case 2: 
                path=files.getSdcardPath();
                break;
            case 3:
                path=files.join( path, searchByName( dialogs.input("输入要搜索的关键字，支持多关键字搜索，使用空格分隔"), items, 4)
                                                .substring(2));//搜索时会将前缀特殊符号带进去搜，所以需要截断
                break;
            default: 
                var t;
                if(ch<items.length-dirList.length){
                    t=fileList[ch-(items.length-fileList.length-dirList.length)];
                }else{
                    t=dirList[ch-(items.length-dirList.length)];
                }
                path=files.join( path, t);
        }
    }
    if(files.isFile(path)){
        return path;
    } else {
        toastLog("选择文件错误！"+"\n"+path);
        return null;
    }
    //随机返回一个前缀
    function randomIcon(arr){
        if(arr==undefined){
            arr=["❤️","💙","🤎","🧡","💜","💔","💛","🖤","💚","🤍","💖","❣️","💗","💓","💝","💘","💕","💞","💟"
            ,"☮️","✝️","☪️","🕉","☸️","✡️","🔯","🕎","☯️","☦️","🛐"
            ,"⛎","♈️","♉️","♊️","♌️","♎️","♏️","♐️","♑️","♒️","♓️","⚛️"
            ,"㊙️","🈲","💯","🆘","🇨🇳","🏴","🏳️","🏁"
            ,"🌠","🎇","🎆","🌌","🌉","🌃","💫","✨"
            ,"💩"]
        }
        try{
            if(iconArr.length<1){
                throw "更新图标数组";
            }
        }catch(e){ 
            iconArr=arr; 
        }
        return iconArr[random( 0, iconArr.length-1)];
    }
    //搜索 word关键字，arr字符串数组，startIndex起始下标
    function searchByName( word, arr, startIndex){
        var name="";
        word=word.toString().split(" ");
        for(var i=0; i<word.length; i++){
            if(word[i]==""){
                word[i]=" ";//解决无法搜索空格的问题
            }
        }
        var items=["🔎继续搜索"];
        //匹配，将匹配的名字保存到items中
        word.forEach(w=>{
            for(var i=startIndex; i<arr.length; i++){
                if(arr[i].indexOf(w)>-1){
                    var noExists=true;
                    for(var j=0; j<items.length; j++){
                        if(w==items[j]){
                            noExists=false;
                            break;
                        }
                    }
                    if(noExists){
                        items.push(arr[i]);
                    }
                }
            }
        });
        var ch=dialogs.select( "["+word+"]", items);
        if(ch==0){
            try{
                return searchByName( dialogs.input("["+word+"]\n继续搜索"), items, 1);
            }catch(e){}
        }else if(ch>0){
            name=items[ch];
        }
        return name;
    }
}
        `,
        describe: "功能描述"
    },
    {
        title: "标题",
        version: "1.0.0",
        author: "luoluo334",
        code: `代码`,
        describe: "功能描述"
    },
]